第二次课

索引 与 MySQL 索引管理

让数据库"翻字典"——以空间换时间的查询加速器

🎯 学习目标
  • 理解索引"以空间换时间"的本质和工作机制
  • 掌握索引的 4 种分类维度和 5 条设置原则
  • 能用 CREATE INDEX、ALTER TABLE、CREATE TABLE 三种方式创建索引
  • 会用 SHOW INDEX 查看索引、用 DROP INDEX 删除索引
📌 上节课回顾(视图)

上次我们学了视图:一条被命名的 SELECT 语句,本质是虚拟表,能像查表一样使用。学习了 CREATE VIEWALTER VIEWDROP VIEW 五项管理操作。

本次课我们换一种"加速器"——视图是为了"简化查询写法",索引则是为了"提升查询速度"。它们解决的问题不一样。

PART 01 · 概念

7.3 索引(Index)

先理解"索引是什么、为什么需要"。这是后面动手操作的根基。

📚 想象一下:你手上有一本 没有目录、也没有页码 的字典,要查"鼎"这个字。怎么办?只能从第一页开始一页一页翻,直到找到为止。

现在再想象一本 正常字典:前面有拼音目录"D... → 鼎 (第 358 页)"。你只需要花两步——查目录、跳到 358 页——就找到了。

第二种方式快得多,但代价是字典前面多印了几十页目录。这就是数据库 索引 的本质:用一点额外的存储空间,换取查询速度的飞跃。

① 索引的作用:以空间换时间

为什么数据库需要索引?

在大多数业务场景中,数据库 "读"操作的次数远多于"写"操作(一个网站,浏览页面可能上千次,但下单可能就几次)。所以 "如何让读得更快" 成了数据库优化的核心命题。

📖 索引的定义

索引(Index)是数据库中一种 独立于数据本身的辅助数据结构,采用 键值对 的形式存储 —— "键"是要查的内容,"值"是这个内容在数据中的位置。借助索引,数据库可以快速定位到目标数据,避免逐行扫描

字典类比图

数据库索引 ≈ 字典的拼音目录 索引(拼音目录) A → 第 1 页 B → 第 23 页 C → 第 67 页 D → 第 158 页 ★ E → 第 201 页 F → 第 245 页 (很小,能一眼扫完) 查 D 指向 158 页 直接跳转 数据(字典正文,按顺序排列) 第 1-22 页:A 开头的字... 第 23-66 页:B 开头的字... 第 67-157 页:C 开头的字... 第 158 页:鼎 ← 直接到达 第 159-200 页:D 开头其他字... 第 201 页之后:E、F、G... (数据量大)
索引就像字典的拼音目录:体积小,但能让查找直达目标
💬 一句话理解

没有索引:数据库挨个读每一行,找你要的数据 —— 叫"全表扫描"。
有了索引:数据库先查索引,再根据索引指向的位置精准取数据 —— 叫"索引扫描"。

表越大,差距越夸张:100 万行的表,全表扫可能要 1 秒,索引扫可能只要 1 毫秒。

索引也不是免费的

⚠️ 索引的代价
  • 占用额外存储空间:索引本身是一份数据,要存到硬盘上。
  • 降低写入性能:每次 INSERT、UPDATE、DELETE,数据库不仅要改表,还要 同步维护索引。索引越多,写越慢。
  • 需要计算资源维护:MySQL 在后台自动维护索引(重新平衡 B-Tree、调整指针等),消耗 CPU 和内存。

所以索引不是"越多越好"。合适的索引才是好索引,这正是后面"设置原则"要讲的。

② 索引的类型:四个分类维度

索引可以从 4 个不同的角度 进行分类。这 4 个维度是 独立的 —— 同一个索引可以同时被打上多个标签。比如:一个索引可能既是"非聚集索引",又是"复合索引",还是"唯一索引",使用"B-Tree 存储方式"。

01
维度一

按物理存储关系

索引的排列顺序与数据本身的存储顺序是否一致。

聚集索引 非聚集索引
02
维度二

按涉及的列数

索引建立在 1 列还是多列上。

单列索引 复合索引
03
维度三

按索引特征(用途)

索引在数据约束、查询场景上的特殊属性。

普通索引 唯一索引 主键索引 全文索引 空间索引
04
维度四

按存储数据结构

索引底层是用什么数据结构组织的。

B-Tree 索引 Hash 索引

重点理解 1:聚集索引 vs 非聚集索引

📦 聚集索引(Clustered Index)

索引的排列顺序 和数据本身的物理顺序一致

就像一本"按拼音排好序"的字典 —— 翻到 D 那一页,D 开头的字本身就连续排在那里。

每张表只能有一个聚集索引(因为数据物理顺序只有一种)。MySQL 中 主键自动是聚集索引

🔗 非聚集索引(Non-clustered Index)

索引和数据 分开存储,索引里只存"键 + 数据位置"。

就像一本"按出现频率排序的字"的索引 —— 索引里写"鼎 → 158 页",但鼎在正文中的位置和它在索引里的位置毫无关系。

一张表可以有多个非聚集索引。我们后面 CREATE INDEX 创建的,绝大多数都是非聚集索引。

重点理解 2:单列索引 vs 复合索引

💬 区别

单列索引:在一个字段上建索引,比如只对 姓名 建索引。

复合索引:在多个字段上一起建索引,比如对 (姓名, 年龄) 一起建。
适合"经常一起出现在 WHERE 条件里"的字段组合,比如查询 WHERE 姓名='张三' AND 年龄=20

重点理解 3:按特征的 5 种索引

类型说明
普通索引(INDEX)最基础的索引,对值没有限制 —— 允许重复、允许 NULL。
唯一索引(UNIQUE INDEX)索引列的值 不允许重复(但允许 NULL,且可以多个 NULL)。常用于学号、身份证等"逻辑唯一"字段。
主键索引(PRIMARY KEY)特殊的唯一索引,值不允许重复 也不允许 NULL。每张表只有一个,自动是聚集索引。
全文索引(FULLTEXT INDEX)用于文本字段(CHAR/VARCHAR/TEXT)的"模糊全文搜索",比 LIKE 高效得多。
空间索引(SPATIAL INDEX)用于地理位置数据(GEOMETRY 类型),比如查找"附近 1 公里内的餐厅"。

重点理解 4:B-Tree 索引 vs Hash 索引

🌳 B-Tree 索引(默认)

底层是平衡树结构,支持范围查询(如 age > 20)和 排序

MySQL 中 InnoDB 引擎默认使用 B+Tree(B-Tree 的变种)。绝大多数情况下都用它

⚡ Hash 索引

底层是哈希表,等值查询极快(O(1) 时间)。

不支持范围查询、不支持排序。MySQL 中 Memory 引擎默认使用,业务表中很少用。

③ 索引的设置原则:5 条铁律

索引不是越多越好,要"会用"。下面是 5 条核心原则:

  1. 1
    严格限制同一个表上的索引数量。索引会拖慢 INSERT/UPDATE/DELETE 的执行性能。对于使用频度低或不再使用的索引,要及时删除
  2. 2
    对"重复值较多"的列,不建议建索引。比如"性别"字段只有"男/女"两个值 —— 索引扫一半才能锁定,效果还不如直接全表扫。
  3. 3
    对"排序、分组、表连接"涉及的字段建索引,可显著提升检索效率。比如经常在 ORDER BY、GROUP BY、JOIN ON 中出现的字段。
  4. 4
    对视图建立索引,将提升视图的检索效率(这是上节课视图的延伸)。
  5. 5
    注意唯一索引和全文索引对 NULL 的处理方式。唯一索引允许多个 NULL(NULL 不参与"唯一性"判断),全文索引会忽略 NULL 值,使用前要清楚这些差异。

反例对比:什么时候 不应该 建索引?

✅ 适合建索引

• 学生表的 学号(值唯一,常用于查询)

• 订单表的 下单时间(常做范围查询和排序)

• 选课表的 学号 + 课程号(常用于 JOIN)

❌ 不适合建索引

• 学生表的 性别(重复值太多)

• 备注、简介这类 大文本字段(除非用全文索引)

• 几乎从不出现在 WHERE 中的字段

📋 第一部分小结

📋 概念回顾
  • 索引的本质:以空间换时间。用一份独立的"键值对"结构,让查询不必扫全表。
  • 4 个分类维度:物理存储(聚集/非聚集)、列数(单列/复合)、特征(普通/唯一/主键/全文/空间)、数据结构(B-Tree/Hash)。
  • 4 个维度独立组合:一个索引可以同时具备多种属性。
  • 5 条设置原则:限制数量、避免低区分度列、关注排序分组连接列、可对视图建、注意 NULL 处理。
  • 记住代价:索引会拖慢写入并占用空间,不能滥用。

🎯 概念小测

概念题 · 1

关于索引的本质,下列说法 正确 的是?

A. 索引是数据本身的一种压缩存储形式
B. 索引是独立于数据的辅助数据结构,以空间换时间提升查询速度
C. 索引只能加速 SELECT,对所有 INSERT/UPDATE/DELETE 也都有加速作用
D. 索引建得越多,数据库整体性能就越好

✅ 正确答案:B

A 错:索引不是数据的压缩,而是独立的辅助结构;C 错:索引只加速读操作,对写操作反而是负担(要同步维护);D 错:索引过多会占空间、拖慢写。

概念题 · 2

下列字段中,最 不适合 建立索引的是?

A. 学生表的学号 sno(每个值都唯一)
B. 学生表的性别 sex(只有"男/女"两个值)
C. 订单表的下单时间(经常做范围查询)
D. 商品表的分类编号(用于 JOIN 关联)

✅ 正确答案:B

性别字段只有 2 个值,区分度极低 —— 即使用索引定位到"男",也要扫几十万行。重复值越多,索引价值越低。这正是设置原则第 2 条。

概念题 · 3

关于聚集索引和非聚集索引的描述,错误 的是?

A. 聚集索引的排列顺序与数据物理存储顺序一致
B. 一张表只能有一个聚集索引,但可以有多个非聚集索引
C. MySQL 中主键自动是聚集索引
D. 非聚集索引比聚集索引查询速度更快

✅ 正确答案:D

D 错:聚集索引数据和索引在一起,查到索引就拿到数据;非聚集索引拿到的是"位置",还要再去取数据 —— 所以一般 聚集索引更快。其他三项都是聚集/非聚集的核心特征。

PART 02 · 操作

7.4 MySQL 索引管理

概念熟了,开始动手。索引的"创建—查看—删除"三件套,每个都要在自己的 MySQL 上敲一遍。

📦 准备工作:复用上次课的环境

本节继续使用上次课建好的 school 数据库(s 学生、c 课程、sc 选课 三张表)。如果你已经按上次的脚本建好了,这一步可以跳过。如果忘了或者数据被改乱了,下面是简化版的重建脚本,再加一张教师表 t(本节有例子要用):

SQL · 准备环境(按需执行)
USE school;

-- 新增:教师表 t(如果不存在)
CREATE TABLE IF NOT EXISTS t (
  tno VARCHAR(10) PRIMARY KEY,    -- 教师工号
  tn  VARCHAR(20) NOT NULL,       -- 教师姓名
  title VARCHAR(10),                -- 职称
  dept  VARCHAR(20)                 -- 所在学院
);

INSERT IGNORE INTO t VALUES
('t01', '王老师', '教授',   '信息学院'),
('t02', '李老师', '副教授', '信息学院'),
('t03', '张老师', '讲师',   '理学院');
💡 提示

本节所有索引创建例子,请直接在 school 数据库里执行。如果创建索引时报"Duplicate key name",说明同名索引已存在,先用本节"删除索引"的方法删掉再重建即可。

① 创建索引:三种方式

MySQL 中创建索引有 3 种语法路径,加上 Workbench 图形化操作共 4 种。我们重点掌握前 3 种。

语法格式

语法
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX 索引名称
  ON 表名(字段名 [(索引字符长度) [ASC | DESC]] [, ...]);

语法关键字详解

关键字说明
UNIQUE / FULLTEXT / SPATIAL可选,指定索引类型。不写就是普通索引。三选一,不能同时多个。
INDEX 索引名称必填,给索引起一个名字(用于后面查看、删除时引用)。
ON 表名指定索引建在哪张表上。
字段名建索引的字段。1 个就是单列索引,多个用逗号分隔就是复合索引
(索引字符长度)对字符串字段,可只取前 N 个字符建索引(节省空间)。如 sn(6) 表示只对 sn 字段的前 6 个字符建索引。
ASC / DESC排序方向,默认 ASC。

例 1.1 · 创建单列索引

需求:为学生表 s 的姓名字段(sn)建立 普通索引 s_name_index,索引只取 sn 的前 6 个字节,并以 降序 方式排列。

SQL
CREATE INDEX s_name_index
  ON s(sn(6) DESC);
💬 这条语句怎么读?

"创建索引,名字叫 s_name_index建在s 的字段 sn 上,只取前 6 个字符,以 降序 排列。"

没写 UNIQUE/FULLTEXT/SPATIAL,所以是 普通索引。后面可以验证一下:

SQL · 验证索引创建成功
SHOW INDEX FROM s;
📊 输出(节选关键列)
TableNon_uniqueKey_nameColumn_nameSub_partCollation
s0PRIMARYsnoNULLA
s1s_name_indexsn6D

例 1.2 · 创建复合唯一索引

需求:为课程表 c 的课程名(cn)和学时(ct)字段建立 复合唯一索引 c_cn_ct_index

SQL
CREATE UNIQUE INDEX c_cn_ct_index
  ON c(cn, ct);
💬 关键点

UNIQUE 关键字 → 唯一索引,要求 (cn, ct) 这个 组合 不能重复(注意:不是单个 cn 唯一,也不是单个 ct 唯一,而是"两个值合起来"必须唯一)。

② 字段写了 2 个(用逗号隔开)→ 复合索引。

③ 复合索引中字段的 顺序很重要 —— 查询条件中只有用到了 cn(或 cn + ct)的查询才能用上这个索引;如果只用 ct 查,这个索引用不上(这就是数据库里著名的"最左前缀原则")。

语法格式

CREATE TABLE 时,在最后的列约束之后 直接附加索引定义:

语法
CREATE TABLE 表名(
  属性名1 数据类型 [列约束],
  ...
  属性名n 数据类型 [列约束],
  [表约束],
  [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY 索引名1 (字段名 [(长度) [ASC|DESC]]),
  ...
  [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY 索引名n (字段名 [(长度) [ASC|DESC]])
);
💬 语法读法

建表时,把字段定义和索引定义写在同一个括号里。索引定义和列定义之间用逗号分隔。

INDEXKEY同义词,写哪个都行(KEY 更短)。

例 2 · 建表附加索引

需求:创建教室表 classroom,包含自增主键 cid、教室编号 crno(非空)、教室所在教学楼 cbn(非空)。同时附加一个由 (crno, cbn) 构成的 复合唯一索引 cn_cb_index

SQL · 完整可执行
CREATE TABLE classroom (
  cid  INT AUTO_INCREMENT,           -- 自增主键
  crno VARCHAR(10) NOT NULL,         -- 教室编号
  cbn  VARCHAR(10) NOT NULL,         -- 教学楼
  PRIMARY KEY(cid),
  UNIQUE INDEX cn_cb_index(crno, cbn)   -- 在这里附加索引
);

-- 验证
SHOW INDEX FROM classroom;
📊 SHOW INDEX 输出
Key_nameNon_uniqueColumn_nameSeq_in_index
PRIMARY0cid1
cn_cb_index0crno1
cn_cb_index0cbn2
💡 适用场景

当你 建表的同时就明确知道要建哪些索引(例如根据需求文档已经设计好),用这种方式最简洁 —— 不用建完表再单独执行 CREATE INDEX

语法格式

语法
ALTER TABLE 表名
  ADD [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY 索引名1 (字段名 [(长度) [ASC|DESC]]),
  ...
  ADD [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY 索引名n (字段名 [(长度) [ASC|DESC]]);
💬 语法读法

"修改表 → 添加索引"。一条语句可以 添加多个索引(每个索引前面都要 ADD)。

例 3 · 给已有表添加索引

需求:为教师表 t 的姓名字段 tn 添加索引 tn_index,索引长度为 6,使用降序排列。

SQL
ALTER TABLE t
  ADD INDEX tn_index(tn(6) DESC);

-- 验证
SHOW INDEX FROM t;
📊 输出(节选)
TableKey_nameColumn_nameSub_partCollation
tPRIMARYtnoNULLA
ttn_indextn6D

一次添加多个索引

ALTER TABLE 还可以"批量添加",比逐条执行效率高(只锁表一次):

SQL · 批量添加
ALTER TABLE t
  ADD INDEX idx_title(title),
  ADD INDEX idx_dept(dept);
💡 三种方式怎么选?

建表时就需要 → 方式 2(建表附加,最简洁)

表已存在,想加单个索引 → 方式 1(CREATE INDEX,语法直观)

表已存在,想一次加多个 → 方式 3(ALTER TABLE 批量)

注意:CREATE INDEX 不能用来创建主键索引(主键只能在建表时或 ALTER TABLE ADD PRIMARY KEY 时创建)。

使用 MySQL Workbench 图形化创建索引

对不喜欢敲 SQL 的同学,Workbench 也提供了图形化方式:

  1. Navigator 窗格的 Schemas 选项卡下,展开目标数据库下的 Tables 节点;
  2. 展开要建索引的表,右键点击 Indexes 下的 PRIMARY 节点,从弹出菜单中选择 Create Index...
  3. 在右侧的窗口中,勾选要建索引的列;
  4. 点击 Create Index For Selected Columns 按钮;
  5. 填写索引名称、字段长度、索引类型(普通/唯一/全文)、索引算法、并发锁管理策略等;
  6. 点击 Apply 提交。
💡 工程建议

Workbench 图形化方式适合 偶尔操作。但学好 SQL 命令更重要 —— 因为:① 服务器没图形界面时只能敲命令;② 自动化脚本必须是命令;③ 团队协作要把建索引语句写进数据库迁移脚本里。

② 查看索引:SHOW INDEX

语法格式

语法
SHOW INDEX FROM 表名 [FROM 数据库名];
💬 语法读法

"显示来自 某张表的索引信息"。可选的 FROM 数据库名 用于跨库查询。

例子:查看学生表 s 的索引

SQL
SHOW INDEX FROM s;
-- 等价于:SHOW INDEX FROM s FROM school;
📊 输出列说明(关键列)
列名含义
Table表名
Non_unique0=唯一索引,1=非唯一索引
Key_name索引名(PRIMARY 是主键索引)
Seq_in_index该字段在索引中的位置(复合索引看这个判断顺序)
Column_name索引涉及的字段
Sub_part索引字符长度(NULL 表示整列)
Collation排序方式:A=升序,D=降序,NULL=无序
Index_type索引数据结构:BTREE / HASH / FULLTEXT
📌 用 MySQL Workbench 查看索引

在 Navigator 窗格的 Schemas 选项卡下,右键点击表名 → 选择 Alter Table,然后切换到右侧窗口的 Indexes 选项卡,就能看到该表所有索引的详细信息(也可以在这里直接修改索引)。

③ 删除索引:两种语法

MySQL 提供了两种删除索引的语法,效果一样,按习惯选用:

方式 1:ALTER TABLE ... DROP INDEX

语法
ALTER TABLE 表名
  DROP INDEX 索引名;

方式 2:DROP INDEX ... ON 表名

语法
DROP INDEX 索引名 ON 表名;

例子:删除 s 表上的 s_name_index

写法 A · ALTER TABLE
ALTER TABLE s
DROP INDEX s_name_index;

动词是"修改表",索引是被修改的内容。

写法 B · DROP INDEX
DROP INDEX s_name_index ON s;

动词是"删除索引",更直接。

💡 两种写法等价

两种语法 底层执行的是同一个操作,性能也一样。选哪个看你的习惯:写法 B 更短更直接,写法 A 和"添加索引"的 ALTER TABLE 写法对称(如果你已经习惯了 ADD INDEX,DROP INDEX 也用 ALTER TABLE 形式更统一)。

⚠️ 注意事项

• 删除索引是 不可逆操作,删除前最好用 SHOW INDEX FROM 表名 把索引信息记下来。

• 不能用 DROP INDEX 删除主键索引(PRIMARY KEY),删除主键要用 ALTER TABLE ... DROP PRIMARY KEY

• 索引名要和 SHOW INDEX 中的 Key_name 一致,大小写敏感

📋 第二部分小结

📋 操作命令速查
  • 创建索引
    CREATE [UNIQUE/FULLTEXT/SPATIAL] INDEX 名 ON 表(字段[(长度) [ASC/DESC]])
    ② 建表时附加 ... INDEX 名(字段)
    ALTER TABLE 表 ADD INDEX 名(字段)
  • 查看索引SHOW INDEX FROM 表名;
  • 删除索引ALTER TABLE 表 DROP INDEX 名DROP INDEX 名 ON 表
  • 关键概念:复合索引 = 多个字段;唯一索引 = 加 UNIQUE;索引字符长度 = 字段名后跟 (N)

✏️ 综合练习

以下题目综合了 索引概念MySQL 操作。先想答案,再点选项验证。

综合题 · 1

下列 SQL 语句 语法正确 的是?

A. CREATE INDEX idx ON s WHERE sn LIKE '王%';
B. CREATE UNIQUE INDEX idx_sn ON s(sn(10));
C. CREATE INDEX UNIQUE idx ON s(sno);
D. ALTER TABLE s INDEX idx_age(age);

✅ 正确答案:B

A 错:CREATE INDEX 没有 WHERE 子句(索引不能"带条件");C 错:UNIQUE 必须放在 INDEX 前面;D 错:ALTER TABLE 添加索引必须用 ADD INDEX,不能省略 ADD。B 是标准的"建唯一索引、字段长度限制为 10"的写法。

综合题 · 2

执行 CREATE INDEX idx_dept_age ON s(dept, age); 后,下列哪个查询 可以利用 这个索引?

A. SELECT * FROM s WHERE dept='信息学院' AND age=20;
B. SELECT * FROM s WHERE age=20;
C. SELECT * FROM s WHERE sn='张三';
D. SELECT * FROM s ORDER BY sno;

✅ 正确答案:A

这是 最左前缀原则:复合索引 (dept, age) 中,字段顺序是 dept 在前。查询条件中 必须用到 dept(最左字段),索引才生效。
A:用了 dept + age → 完美命中; B:只用 age 没用 dept → 用不上; C:用了 sn 不在索引里 → 用不上; D:按 sno 排序,索引也无关。

综合题 · 3

想要删除表 t 上名为 tn_index 的索引,下列 都正确 的是?

A. 只有 DROP INDEX tn_index ON t;
B. 只有 ALTER TABLE t DROP INDEX tn_index;
C. A 和 B 都正确
D. DELETE INDEX tn_index FROM t;

✅ 正确答案:C

MySQL 提供了 两种等价的删除索引语法DROP INDEX 索引名 ON 表名ALTER TABLE 表名 DROP INDEX 索引名,效果完全相同。D 是错的 —— SQL 中没有 DELETE INDEX 这种语法。

综合题 · 4

下列描述中 错误 的是?

A. 主键索引、唯一索引、普通索引都属于"按特征"的分类
B. 一张表可以有多个非聚集索引,但只能有一个聚集索引
C. 索引数量越多,数据库整体性能越好
D. 对"性别"这种重复值多的字段,不建议建索引

✅ 正确答案:C

C 是 反向错误:索引会拖慢 INSERT/UPDATE/DELETE 性能(每次写都要维护索引)。索引"宁缺毋滥"。其他三项都正确。

综合题 · 5

想为 sc 表的 (sno, cno) 两个字段建立 复合普通索引,下列 不正确 的是?

A. CREATE INDEX idx_s_c ON sc(sno, cno);
B. ALTER TABLE sc ADD INDEX idx_s_c(sno, cno);
C. CREATE INDEX idx_s_c ON sc(sno) AND ON sc(cno);
D. 在建表时附加 INDEX idx_s_c(sno, cno)

✅ 正确答案:C

C 是错的 —— SQL 中没有"AND ON"这种语法。复合索引 所有字段写在同一个括号里,用逗号分隔(A、B、D 都是这样)。注意:A 和 B 是 建一个复合索引不是 建两个单列索引。

🛠️ 实操任务(课后练习)

以下任务请在自己的 MySQL 环境中实际执行,并用 SHOW INDEX FROM 表名 验证。

任务 1 · 基础

为学生表 s 的年龄字段 age 建立 普通索引,名为 idx_age,使用 升序 排列。

查看参考答案
SQL
CREATE INDEX idx_age
  ON s(age ASC);

-- 验证
SHOW INDEX FROM s;

ASC 是默认值,可以省略不写。

任务 2 · 中等

ALTER TABLE 一次性给课程表 c 添加两个索引:
① 课程名 cn唯一索引,名为 uk_cn
② 学时 ct普通索引,名为 idx_ct

查看参考答案
SQL
ALTER TABLE c
  ADD UNIQUE INDEX uk_cn(cn),
  ADD INDEX idx_ct(ct);

SHOW INDEX FROM c;

如果已经在前面创建过 c_cn_ct_indexcn 字段上可能已有相关索引;执行前可先 DROP

任务 3 · 综合(思考 + 实操)

① 为 sc 表创建一个复合索引 idx_sno_cno,包含 (sno, cno)
② 然后用 SHOW INDEX FROM sc 查看;
③ 思考并回答:下列两个查询,哪一个能用上这个索引?
  查询甲:SELECT * FROM sc WHERE sno='s01' AND cno='c01';
  查询乙:SELECT * FROM sc WHERE cno='c01';
④ 最后用 两种语法 分别删除这个索引(先删一次,再创建一次,再用另一种方式删除)。

查看参考答案
SQL · 完整流程
-- ① 创建复合索引
CREATE INDEX idx_sno_cno ON sc(sno, cno);

-- ② 查看
SHOW INDEX FROM sc;

-- ④a 用 DROP INDEX 语法删除
DROP INDEX idx_sno_cno ON sc;

-- 重新创建一次
CREATE INDEX idx_sno_cno ON sc(sno, cno);

-- ④b 用 ALTER TABLE 语法删除
ALTER TABLE sc
  DROP INDEX idx_sno_cno;

③ 思考题答案
查询甲能用上索引 —— 用到了复合索引最左字段 sno
查询乙用不上索引 —— 没用 sno,违反"最左前缀原则"。
如果业务中乙这种"只查 cno"的查询很常见,应该单独为 cno 建一个索引。